/**  
* Copyright (c) 2008, Noel Lynch All rights reserved. Redistribution and use  
* in source and binary forms, with or without modification, are permitted  
* provided that the following conditions are met: Redistributions of source  
* code must retain the above copyright notice, this list of conditions and the  
* following disclaimer. Redistributions in binary form must reproduce the above  
* copyright notice, this list of conditions and the following disclaimer in the  
* documentation and/or other materials provided with the distribution. Neither  
* the name of Noel Lynch nor the names of contributors may be used to  
* endorse or promote products derived from this software without specific prior  
* written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*/
// Jul 23, 2008

package com.sceneworker.extensions.texturestate;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import com.acarter.propertytable.Property;
import com.acarter.propertytable.PropertySection;
import com.acarter.propertytable.PropertySectionState;
import com.acarter.propertytable.PropertyTable;
import com.acarter.propertytable.propertyobject.EnumPropertyObject;
import com.acarter.propertytable.propertyobject.EnumPropertyObject.I_EnumPropertyObjectListener;
import com.acarter.propertytable.propertyobject.IntegerPropertyObject;
import com.acarter.propertytable.propertyobject.StringPropertyObject;
import com.acarter.propertytable.propertyobject.IntegerPropertyObject.I_IntegerPropertyObjectListener;
import com.acarter.propertytable.propertyobject.StringPropertyObject.I_StringPropertyObjectListener;
import com.acarter.scenemonitor.propertydescriptor.definitions.renderstate.TextureStatePropertyPage;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.ColorRGBAPropertyObject;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.QuaternionPropertyObject;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.Vector3fPropertyObject;
import com.sceneworker.extensions.ExtPropertySection;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.image.Texture.EnvironmentalMapMode;
import com.jme.image.Texture.WrapAxis;
import com.jme.image.Texture.WrapMode;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.TextureState.CorrectionType;
import com.jme.util.TextureKey;
import com.jme.util.TextureManager;


public class ExtTexturestatePropertyPage extends TextureStatePropertyPage {

	private		ArrayList<TextureSectionEntryData>		mcla_textureSections;
	
	public ExtTexturestatePropertyPage() {
		super();
		
		// create a new seciton
		ExtPropertySection section = new ExtPropertySection("Textures");
		
		// add a property..string
		section.addProperty(new Property("Texture Units", new TextureUnitsPropertyObject()));
		
		// set the state of it
		section.setState(PropertySectionState.EXPANDED);
		
		// add it to the model
		model.addPropertySection(section);
		
		mcla_textureSections = new ArrayList<TextureSectionEntryData>();
	}
	
	@Override
	public void updateModel(PropertyTable table, Object object) {

		if(object instanceof RenderState) {
			
			RenderState state = (RenderState)object;
			
			updateListeners(state);
		}
	}
	
	private	int		textureUnitInSectionsArray(int i_tu) {
		for(int li_index = 0; li_index < mcla_textureSections.size(); li_index++) {
			if(mcla_textureSections.get(li_index).exists(i_tu)) {
				return li_index;
			}
		}
		
		return -1;
	}
	
	protected	void
	updateUnitsField(final TextureState cl_state) {
		ExtPropertySection		lcl_texturePropSection = (ExtPropertySection)model.getPropertySection("Textures");
		
		// update the number of texture units
		TextureUnitsPropertyObject lcl_numTUnits = (TextureUnitsPropertyObject)lcl_texturePropSection.getProperty("Texture Units").getPropertyObject();
		
		lcl_numTUnits.SetListener(new TextureUnitsPropertyObject.I_TextureUnitsPropertyObjectListener() {
			public TextureState readValue() {
				return cl_state;
			}

			public void saveValue(TextureState value) {}
		});
	}
	
	private	TextureSectionEntryData
	buildTextureSection(int i_textureUnit) {
		PropertySection		lcl_textureSection = new PropertySection("Texture " + i_textureUnit);
		lcl_textureSection.addProperty(new Property("Texture ID", new IntegerPropertyObject()));
		lcl_textureSection.addProperty(new Property("Location of Texture", new TextureLocationPropertyObject()));
		lcl_textureSection.addProperty(new Property("Texture Position", new Vector3fPropertyObject()));
		lcl_textureSection.addProperty(new Property("Texture Scale", new Vector3fPropertyObject()));
		lcl_textureSection.addProperty(new Property("Texture Rotation", new QuaternionPropertyObject()));
		lcl_textureSection.addProperty(new Property("Wrap on S", new EnumPropertyObject<Texture.WrapMode>()));
		lcl_textureSection.addProperty(new Property("Wrap on T", new EnumPropertyObject<Texture.WrapMode>()));
		lcl_textureSection.addProperty(new Property("Min Filter", new EnumPropertyObject<Texture.MinificationFilter>()));
		lcl_textureSection.addProperty(new Property("Mag Filter", new EnumPropertyObject<Texture.MagnificationFilter>()));
		lcl_textureSection.addProperty(new Property("Apply Mode", new EnumPropertyObject<Texture.ApplyMode>()));
		
		PropertySection		lcl_advancedSections = new PropertySection("Texture Extra " + i_textureUnit);
		lcl_advancedSections.addProperty(new Property("Env Map Mode", new EnumPropertyObject<Texture.EnvironmentalMapMode>()));
		lcl_advancedSections.addProperty(new Property("Blend Colour", new ColorRGBAPropertyObject()));
		lcl_advancedSections.addProperty(new Property("Combine Func Alpha", new EnumPropertyObject<Texture.CombinerFunctionAlpha>()));
		lcl_advancedSections.addProperty(new Property("Combine Func RGB", new EnumPropertyObject<Texture.CombinerFunctionRGB>()));
		lcl_advancedSections.addProperty(new Property("Combine Op 0 Alpha", new EnumPropertyObject<Texture.CombinerOperandAlpha>()));
		lcl_advancedSections.addProperty(new Property("Combine Op 0 RGB", new EnumPropertyObject<Texture.CombinerOperandRGB>()));
		lcl_advancedSections.addProperty(new Property("Combine Op 1 Alpha", new EnumPropertyObject<Texture.CombinerOperandAlpha>()));
		lcl_advancedSections.addProperty(new Property("Combine Op 1 RGB", new EnumPropertyObject<Texture.CombinerOperandRGB>()));
		lcl_advancedSections.addProperty(new Property("Combine Op 2 Alpha", new EnumPropertyObject<Texture.CombinerOperandAlpha>()));
		lcl_advancedSections.addProperty(new Property("Combine Op 2 RGB", new EnumPropertyObject<Texture.CombinerOperandRGB>()));
		lcl_advancedSections.addProperty(new Property("Combine Scale Alpha", new EnumPropertyObject<Texture.CombinerScale>()));
		lcl_advancedSections.addProperty(new Property("Combine Scale RGB", new EnumPropertyObject<Texture.CombinerScale>()));
		lcl_advancedSections.addProperty(new Property("Combine Src 0 Alpha", new EnumPropertyObject<Texture.CombinerSource>()));
		lcl_advancedSections.addProperty(new Property("Combine Src 0 RGB", new EnumPropertyObject<Texture.CombinerSource>()));
		lcl_advancedSections.addProperty(new Property("Combine Src 1 Alpha", new EnumPropertyObject<Texture.CombinerSource>()));
		lcl_advancedSections.addProperty(new Property("Combine Src 1 RGB", new EnumPropertyObject<Texture.CombinerSource>()));
		lcl_advancedSections.addProperty(new Property("Combine Src 2 Alpha", new EnumPropertyObject<Texture.CombinerSource>()));
		lcl_advancedSections.addProperty(new Property("Combine Src 2 RGB", new EnumPropertyObject<Texture.CombinerSource>()));
		lcl_advancedSections.setState(false);
		
		model.addPropertySection(lcl_textureSection);
		model.addPropertySection(lcl_advancedSections);
		
		TextureSectionEntryData		lcl_tsection = new TextureSectionEntryData();
		lcl_tsection.mcl_textureSection = lcl_textureSection;
		lcl_tsection.mcl_advTextureSection = lcl_advancedSections;
		lcl_tsection.mi_textureUnit = i_textureUnit;
		return lcl_tsection;
	}
	
	class	TextureSectionEntryData {
		public	PropertySection		mcl_textureSection;
		public	PropertySection		mcl_advTextureSection;
		public	int					mi_textureUnit;
		
		public	boolean		exists(int i_tu) {
			if(mi_textureUnit == i_tu) {
				return true;
			}
			
			return false;
		}
	}
	
	protected	void
	updateTextureSections(final TextureState cl_state) {
		// are the textures added
		int		li_numT = cl_state.getNumberOfSetTextures();
		
		// gone out of whack so clear up
		if(mcla_textureSections.size() > li_numT) {
			for(TextureSectionEntryData lcl_section : mcla_textureSections) {
				model.removePropertySection(lcl_section.mcl_advTextureSection);
				model.removePropertySection(lcl_section.mcl_textureSection);
			}
			mcla_textureSections.clear();
		}
		
		// populate our sections array and build the texture sections
		for(int li_tuIndex = 0; li_tuIndex < cl_state.getNumberOfSetTextures(); li_tuIndex++) {
			if(cl_state.getTexture(li_tuIndex) != null) {		// a texture exists
				if(textureUnitInSectionsArray(li_tuIndex) == -1) {		// is it already in our array
					mcla_textureSections.add(buildTextureSection(li_tuIndex));		// no then add it
				}
			} else {	// texture is null..it may of been removed
				int		li_arrayIndex = textureUnitInSectionsArray(li_tuIndex);
				if(li_arrayIndex != -1) {		// is it in our sections array
					model.removePropertySection(mcla_textureSections.get(li_arrayIndex).mcl_advTextureSection);
					model.removePropertySection(mcla_textureSections.get(li_arrayIndex).mcl_textureSection);
					mcla_textureSections.remove(li_arrayIndex);		// yes..then we need to remove it
				}
			}
		}
		
		// update each property
		for(int li_i = 0; li_i < mcla_textureSections.size(); li_i++) {
			final	Texture		lcl_texture = cl_state.getTexture(mcla_textureSections.get(li_i).mi_textureUnit);
			if(lcl_texture != null) {
				updateTextureSection(cl_state, lcl_texture, mcla_textureSections.get(li_i).mi_textureUnit);
			}
		}
		
		cl_state.setNeedsRefresh(true);
	}
	
	protected	void
	updateTextureSection(final TextureState cl_textureState, final Texture cl_texture, final int i_unit) {
		final	ExtTexturestatePropertyPage		lcl_this = this;
		
		PropertySection		lcl_textureSection = model.getPropertySection("Texture " + i_unit);
		PropertySection		lcl_advancedSection = model.getPropertySection("Texture Extra " + i_unit);
		
		// combine op 2 alpha
		EnumPropertyObject<Texture.CombinerSource>		lcl_combineSrc2Alpha = (EnumPropertyObject<Texture.CombinerSource>)
										lcl_advancedSection.getProperty("Combine Src 2 Alpha").getPropertyObject();
		lcl_combineSrc2Alpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerSource>() {
			public Texture.CombinerSource readValue() {
				return cl_texture.getCombineSrc2Alpha();
			}

			public void saveValue(Texture.CombinerSource value) {
				cl_texture.setCombineSrc2Alpha(value);
			}
			
		});
		
		// combine scale alpha
		EnumPropertyObject<Texture.CombinerSource>		lcl_combineSrc2RGB = (EnumPropertyObject<Texture.CombinerSource>)
										lcl_advancedSection.getProperty("Combine Src 2 RGB").getPropertyObject();
		lcl_combineSrc2RGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerSource>() {
			public Texture.CombinerSource readValue() {
				return cl_texture.getCombineSrc2RGB();
			}

			public void saveValue(Texture.CombinerSource value) {
				cl_texture.setCombineSrc2RGB(value);
			}
			
		});
		
		// combine op 2 alpha
		EnumPropertyObject<Texture.CombinerSource>		lcl_combineSrc1Alpha = (EnumPropertyObject<Texture.CombinerSource>)
										lcl_advancedSection.getProperty("Combine Src 1 Alpha").getPropertyObject();
		lcl_combineSrc1Alpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerSource>() {
			public Texture.CombinerSource readValue() {
				return cl_texture.getCombineSrc1Alpha();
			}

			public void saveValue(Texture.CombinerSource value) {
				cl_texture.setCombineSrc1Alpha(value);
			}
			
		});
		
		// combine scale alpha
		EnumPropertyObject<Texture.CombinerSource>		lcl_combineSrc1RGB = (EnumPropertyObject<Texture.CombinerSource>)
										lcl_advancedSection.getProperty("Combine Src 1 RGB").getPropertyObject();
		lcl_combineSrc1RGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerSource>() {
			public Texture.CombinerSource readValue() {
				return cl_texture.getCombineSrc1RGB();
			}

			public void saveValue(Texture.CombinerSource value) {
				cl_texture.setCombineSrc1RGB(value);
			}
			
		});
		
		// combine op 2 alpha
		EnumPropertyObject<Texture.CombinerSource>		lcl_combineSrc0Alpha = (EnumPropertyObject<Texture.CombinerSource>)
										lcl_advancedSection.getProperty("Combine Src 0 Alpha").getPropertyObject();
		lcl_combineSrc0Alpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerSource>() {
			public Texture.CombinerSource readValue() {
				return cl_texture.getCombineSrc0Alpha();
			}

			public void saveValue(Texture.CombinerSource value) {
				cl_texture.setCombineSrc0Alpha(value);
			}
			
		});
		
		// combine scale alpha
		EnumPropertyObject<Texture.CombinerSource>		lcl_combineSrc0RGB = (EnumPropertyObject<Texture.CombinerSource>)
										lcl_advancedSection.getProperty("Combine Src 0 RGB").getPropertyObject();
		lcl_combineSrc0RGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerSource>() {
			public Texture.CombinerSource readValue() {
				return cl_texture.getCombineSrc0RGB();
			}

			public void saveValue(Texture.CombinerSource value) {
				cl_texture.setCombineSrc0RGB(value);
			}
			
		});
		
		// combine scale alpha
		EnumPropertyObject<Texture.CombinerScale>	lcl_combineScaleRGB = (EnumPropertyObject<Texture.CombinerScale>)
										lcl_advancedSection.getProperty("Combine Scale RGB").getPropertyObject();
		lcl_combineScaleRGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerScale>() {
			public Texture.CombinerScale readValue() {
				return cl_texture.getCombineScaleRGB();
			}

			public void saveValue(Texture.CombinerScale value) {
				cl_texture.setCombineScaleRGB(value);
			}
			
		});
		
		// combine op 2 alpha
		EnumPropertyObject<Texture.CombinerScale>	lcl_combineScaleAlpha = (EnumPropertyObject<Texture.CombinerScale>)
										lcl_advancedSection.getProperty("Combine Scale Alpha").getPropertyObject();
		lcl_combineScaleAlpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerScale>() {
			public Texture.CombinerScale readValue() {
				return cl_texture.getCombineScaleAlpha();
			}

			public void saveValue(Texture.CombinerScale value) {
				cl_texture.setCombineScaleAlpha(value);
			}
			
		});
		
		// combine op 2 rgb
		EnumPropertyObject<Texture.CombinerOperandRGB>	lcl_combineOp2RGB = (EnumPropertyObject<Texture.CombinerOperandRGB>)
										lcl_advancedSection.getProperty("Combine Op 2 RGB").getPropertyObject();
		lcl_combineOp2RGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerOperandRGB>() {
			public Texture.CombinerOperandRGB readValue() {
				return cl_texture.getCombineOp2RGB();
			}

			public void saveValue(Texture.CombinerOperandRGB value) {
				cl_texture.setCombineOp2RGB(value);
			}
			
		});
		
		// combine op 2 alpha
		EnumPropertyObject<Texture.CombinerOperandAlpha>	lcl_combineOp2Alpha = (EnumPropertyObject<Texture.CombinerOperandAlpha>)
										lcl_advancedSection.getProperty("Combine Op 2 Alpha").getPropertyObject();
		lcl_combineOp2Alpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerOperandAlpha>() {
			public Texture.CombinerOperandAlpha readValue() {
				return cl_texture.getCombineOp2Alpha();
			}

			public void saveValue(Texture.CombinerOperandAlpha value) {
				cl_texture.setCombineOp2Alpha(value);
			}
			
		});
		
		// combine op 1 alpha
		EnumPropertyObject<Texture.CombinerOperandRGB>	lcl_combineOp1RGB = (EnumPropertyObject<Texture.CombinerOperandRGB>)
										lcl_advancedSection.getProperty("Combine Op 1 RGB").getPropertyObject();
		lcl_combineOp1RGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerOperandRGB>() {
			public Texture.CombinerOperandRGB readValue() {
				return cl_texture.getCombineOp1RGB();
			}

			public void saveValue(Texture.CombinerOperandRGB value) {
				cl_texture.setCombineOp1RGB(value);
			}
			
		});
		
		// combine op 1 alpha
		EnumPropertyObject<Texture.CombinerOperandAlpha>	lcl_combineOp1Alpha = (EnumPropertyObject<Texture.CombinerOperandAlpha>)
										lcl_advancedSection.getProperty("Combine Op 1 Alpha").getPropertyObject();
		lcl_combineOp1Alpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerOperandAlpha>() {
			public Texture.CombinerOperandAlpha readValue() {
				return cl_texture.getCombineOp1Alpha();
			}

			public void saveValue(Texture.CombinerOperandAlpha value) {
				cl_texture.setCombineOp1Alpha(value);
			}
			
		});
		
		// combine op 0 alpha
		EnumPropertyObject<Texture.CombinerOperandRGB>	lcl_combineOp0RGB = (EnumPropertyObject<Texture.CombinerOperandRGB>)
										lcl_advancedSection.getProperty("Combine Op 0 RGB").getPropertyObject();
		lcl_combineOp0RGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerOperandRGB>() {
			public Texture.CombinerOperandRGB readValue() {
				return cl_texture.getCombineOp0RGB();
			}

			public void saveValue(Texture.CombinerOperandRGB value) {
				cl_texture.setCombineOp0RGB(value);
			}
			
		});
		
		// combine op 0 alpha
		EnumPropertyObject<Texture.CombinerOperandAlpha>	lcl_combineOp0Alpha = (EnumPropertyObject<Texture.CombinerOperandAlpha>)
										lcl_advancedSection.getProperty("Combine Op 0 Alpha").getPropertyObject();
		lcl_combineOp0Alpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerOperandAlpha>() {
			public Texture.CombinerOperandAlpha readValue() {
				return cl_texture.getCombineOp0Alpha();
			}

			public void saveValue(Texture.CombinerOperandAlpha value) {
				cl_texture.setCombineOp0Alpha(value);
			}
			
		});
		
		TextureLocationPropertyObject		lcl_textureLocation = (TextureLocationPropertyObject)lcl_textureSection.getProperty("Location of Texture").getPropertyObject();
		
		final	String		lstr_temp = cl_texture.getImageLocation();
		
		lcl_textureLocation.SetListener(new TextureLocationPropertyObject.I_TextureLocationPropertyObjectListener() {
			public String readValue() {
				
				return lstr_temp;
			}

			public void saveValue(String str_value) {
				if(!str_value.equals(lstr_temp)) {
					try {
						Image		lcl_im = TextureManager.loadImage(new URL(str_value), true);
						cl_texture.setImage(lcl_im);
						cl_texture.setImageLocation(str_value);
						cl_texture.getTextureKey().setLocation(new URL(str_value));
						cl_texture.setTextureId(0);
						lcl_this.setUpdate(true);

					} catch (MalformedURLException e) {
						e.printStackTrace();
					}
				}
								
			}
		});
		
		// update the ID
		IntegerPropertyObject		lcl_textureID = (IntegerPropertyObject)lcl_textureSection.getProperty("Texture ID").getPropertyObject();
		lcl_textureID.SetListener(new IntegerPropertyObject.I_IntegerPropertyObjectListener() {

			public int readValue() {
				return cl_texture.getTextureId();
			}

			public void saveValue(int value) {
			}
			
		});
		
		// update the scale
		Vector3fPropertyObject		lcl_texturePosition = (Vector3fPropertyObject)lcl_textureSection.getProperty("Texture Position").getPropertyObject();
		
		lcl_texturePosition.SetListener(new Vector3fPropertyObject.I_Vector3fPropertyObjectListener() {

			public Vector3f readValue() {
				if(cl_texture.getTranslation() == null) {
					cl_texture.setTranslation(new Vector3f());
				}
				
				return cl_texture.getTranslation();
			}

			public void saveValue(Vector3f value) {
				System.out.println("setting pos of texture to " + value);
				cl_texture.setTranslation(value);
			}
			
		});
		
		// update the scale
		Vector3fPropertyObject		lcl_textureScale = (Vector3fPropertyObject)lcl_textureSection.getProperty("Texture Scale").getPropertyObject();
		
		lcl_textureScale.SetListener(new Vector3fPropertyObject.I_Vector3fPropertyObjectListener() {

			public Vector3f readValue() {
				if(cl_texture.getScale() == null) {
					cl_texture.setScale(new Vector3f(1, 1, 1));
				}
				
				return cl_texture.getScale();
			}

			public void saveValue(Vector3f value) {
				cl_texture.setScale(value);
			}
			
		});
		
		// update the rotation
		QuaternionPropertyObject	lcl_textureRot = (QuaternionPropertyObject)lcl_textureSection.getProperty("Texture Rotation").getPropertyObject();
		
		lcl_textureRot.SetListener(new QuaternionPropertyObject.I_QuaternionPropertyObjectListener() {

			public Quaternion readValue() {
				if(cl_texture.getRotation() == null) {
					cl_texture.setRotation(new Quaternion());
				}
				
				return cl_texture.getRotation();
			}

			public void saveValue(Quaternion value) {
				cl_texture.setRotation(value);
			}
			
		});
		
		// update the wrap mode for s
		EnumPropertyObject<Texture.WrapMode>	lcl_wrapModeS = (EnumPropertyObject<Texture.WrapMode>)lcl_textureSection.getProperty("Wrap on S").getPropertyObject();
		
		lcl_wrapModeS.SetListener(new I_EnumPropertyObjectListener<WrapMode>() {

			public WrapMode readValue() {
				return cl_texture.getWrap(WrapAxis.S);
			}

			public void saveValue(WrapMode value) {
				cl_texture.setWrap(WrapAxis.S, value);
			}
			
		});
		
		// update the wrap mode for t
		EnumPropertyObject<Texture.WrapMode>	lcl_wrapModeT = (EnumPropertyObject<Texture.WrapMode>)lcl_textureSection.getProperty("Wrap on T").getPropertyObject();
		
		lcl_wrapModeT.SetListener(new I_EnumPropertyObjectListener<WrapMode>() {

			public WrapMode readValue() {
				return cl_texture.getWrap(WrapAxis.T);
			}

			public void saveValue(WrapMode value) {
				cl_texture.setWrap(WrapAxis.T, value);
			}
			
		});
		
		// update the min filter
		EnumPropertyObject<Texture.MinificationFilter>	lcl_minFilter = (EnumPropertyObject<Texture.MinificationFilter>)lcl_textureSection.getProperty("Min Filter").getPropertyObject();
		
		lcl_minFilter.SetListener(new I_EnumPropertyObjectListener<Texture.MinificationFilter>() {

			public Texture.MinificationFilter readValue() {
				return cl_texture.getMinificationFilter();
			}

			public void saveValue(Texture.MinificationFilter value) {
				System.out.println("Min filter " + value);
				cl_texture.setMinificationFilter(value);
			}
			
		});
		
		// update the mag filter
		EnumPropertyObject<Texture.MagnificationFilter>	lcl_magFilter = (EnumPropertyObject<Texture.MagnificationFilter>)lcl_textureSection.getProperty("Mag Filter").getPropertyObject();
		
		lcl_magFilter.SetListener(new I_EnumPropertyObjectListener<Texture.MagnificationFilter>() {

			public Texture.MagnificationFilter readValue() {
				return cl_texture.getMagnificationFilter();
			}

			public void saveValue(Texture.MagnificationFilter value) {
				cl_texture.setMagnificationFilter(value);
			}
			
		});
		
		// update the apply mode
		EnumPropertyObject<Texture.ApplyMode>	lcl_applyMode = (EnumPropertyObject<Texture.ApplyMode>)lcl_textureSection.getProperty("Apply Mode").getPropertyObject();
		
		lcl_applyMode.SetListener(new I_EnumPropertyObjectListener<Texture.ApplyMode>() {

			public Texture.ApplyMode readValue() {
				return cl_texture.getApply();
			}

			public void saveValue(Texture.ApplyMode value) {
				cl_texture.setApply(value);
			}
			
		});
		
		// ------------------------
		// advanced...
		
		
		// blend colour
		ColorRGBAPropertyObject		lcl_blendColour = (ColorRGBAPropertyObject)lcl_advancedSection.getProperty("Blend Colour").getPropertyObject();
		lcl_blendColour.SetListener(new ColorRGBAPropertyObject.I_ColorRGBAPropertyObjectListener() {

			public ColorRGBA readValue() {
				if(cl_texture.getBlendColor() == null) {
					cl_texture.setBlendColor(ColorRGBA.black);
				}
				return cl_texture.getBlendColor();
			}

			public void saveValue(ColorRGBA value) {
				cl_texture.setBlendColor(value);
			}
			
		});
		
		// env map mode
		EnumPropertyObject<Texture.EnvironmentalMapMode>	lcl_env = (EnumPropertyObject<Texture.EnvironmentalMapMode>)
										lcl_advancedSection.getProperty("Env Map Mode").getPropertyObject();
		lcl_env.SetListener(new I_EnumPropertyObjectListener<Texture.EnvironmentalMapMode>() {

			public EnvironmentalMapMode readValue() {
				return cl_texture.getEnvironmentalMapMode();
			}

			public void saveValue(EnvironmentalMapMode value) {
				cl_texture.setEnvironmentalMapMode(value);
			}
			
		});
		
		// combine func alpha
		EnumPropertyObject<Texture.CombinerFunctionAlpha>	lcl_combineAlpha = (EnumPropertyObject<Texture.CombinerFunctionAlpha>)
										lcl_advancedSection.getProperty("Combine Func Alpha").getPropertyObject();
		lcl_combineAlpha.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerFunctionAlpha>() {

			public Texture.CombinerFunctionAlpha readValue() {
				return cl_texture.getCombineFuncAlpha();
			}

			public void saveValue(Texture.CombinerFunctionAlpha value) {
				cl_texture.setCombineFuncAlpha(value);
			}
			
		});
		
		// combine func rgb
		EnumPropertyObject<Texture.CombinerFunctionRGB>	lcl_combineRGB = (EnumPropertyObject<Texture.CombinerFunctionRGB>)
										lcl_advancedSection.getProperty("Combine Func RGB").getPropertyObject();
		lcl_combineRGB.SetListener(new I_EnumPropertyObjectListener<Texture.CombinerFunctionRGB>() {

			public Texture.CombinerFunctionRGB readValue() {
				return cl_texture.getCombineFuncRGB();
			}

			public void saveValue(Texture.CombinerFunctionRGB value) {
				cl_texture.setCombineFuncRGB(value);
			}
			
		});
		
		
		
	}
	
	@Override
	protected void updateListeners(final RenderState renderstate) {
		super.updateListeners(renderstate);
		
		//System.out.println("updating");
		
		if(!(renderstate instanceof TextureState))
			return;
		
		final TextureState lcl_textureState = (TextureState)renderstate;
		
		updateUnitsField(lcl_textureState);
		//updateTextureSections(lcl_textureState);
		
	}
}